<template>
  <template v-if="isContextMenuTrigger">
    <span class="dropdown-container" @contextmenu="handleContextMenu">
      <slot name="contextmenu"></slot>
    </span>
    <n-dropdown
      placement="bottom-start"
      trigger="manual"
      :x="xRef"
      :y="yRef"
      :options="options"
      :show="showDropdownRef"
      @clickoutside="onClickoutside"
      @select="handleSelect"
    />
  </template>

  <n-dropdown
    v-else
    placement="bottom-start"
    :trigger="trigger as 'hover' | 'click'"
    :options="options"
    @select="triggerSelect"
  >
    <slot></slot>
  </n-dropdown>
</template>

<script setup lang="ts">
import { ref, nextTick, computed } from "vue";
import { NDropdown } from "naive-ui";
import type {
  DropdownMixedOption,
  Key,
} from "naive-ui/es/dropdown/src/interface";

export type ZDropdownOption = DropdownMixedOption & {
  disabled?: ((option: ZDropdownOption) => boolean) | boolean;
  onSelect?: (option: ZDropdownOption) => void;
};

export interface ZDropdownProps {
  options: ZDropdownOption[];
  trigger?: "hover" | "click" | "contextmenu";
}

const props = withDefaults(defineProps<ZDropdownProps>(), {
  trigger: "hover",
});

const emit = defineEmits<{
  (e: "select", key: Key): void;
}>();

const isContextMenuTrigger = computed(() => props.trigger === "contextmenu");

/* "hover" | "click" */
function triggerSelect(key: Key) {
  emit("select", key);
  const option = props.options.find((op) => op.key === key);
  option?.onSelect?.(option);
}

/* "contextmenu" */
const showDropdownRef = ref(false);
const xRef = ref(0);
const yRef = ref(0);

function handleSelect(key: Key) {
  showDropdownRef.value = false;
  triggerSelect(key);
}
function handleContextMenu(e: MouseEvent) {
  e.preventDefault();
  showDropdownRef.value = false;

  nextTick().then(() => {
    showDropdownRef.value = true;
    xRef.value = e.clientX;
    yRef.value = e.clientY;
  });
}
function onClickoutside() {
  showDropdownRef.value = false;
}
</script>

<style scoped>
.dropdown-container {
  display: flex;
  align-items: center;
}
</style>
